//
//  LZChangeClassName.m
//  LZSpamCode
//
//  Created by ZengLiZhi on 2024/6/26.
//

#import "LZChangeClassName.h"
#import "LZSpamCodeManager.h"
#import "LZFileManager.h"

@implementation LZChangeClassName

+ (void)start{
    
    NSString *gOldProjectName = [LZSpamCodeManager shareInstance].gOldProjectName;
    NSString *gNewProjectName = [LZSpamCodeManager shareInstance].gNewProjectName;
    NSString *gProjectPath = [LZSpamCodeManager shareInstance].gProjectPath;
    
    NSString *gOldClassNamePrefix = [LZSpamCodeManager shareInstance].gOldClassNamePrefix;
    NSString *gNewClassNamePrefix = [LZSpamCodeManager shareInstance].gNewClassNamePrefix;
    
    if (gOldClassNamePrefix && gNewClassNamePrefix) {
        printf("开始修改类名前缀...\n");
        
        NSString *xcodeprojPath = [NSString stringWithFormat:@"%@/%@.xcodeproj",gProjectPath,gNewProjectName];
        NSString *projectFilePath = [xcodeprojPath stringByAppendingPathComponent:@"project.pbxproj"];
        
        NSFileManager *fileManager = [NSFileManager defaultManager];
        BOOL isDirectory = NO;
        
        if (![fileManager fileExistsAtPath:xcodeprojPath isDirectory:&isDirectory] || !isDirectory
            || ![fileManager fileExistsAtPath:projectFilePath isDirectory:&isDirectory] || isDirectory) {
            printf("修改类名前缀的工程文件参数错误。%s \n", xcodeprojPath.UTF8String);
            return ;
        }
        
        @autoreleasepool {
            // 打开工程文件
            NSError *error = nil;
            NSMutableString *projectContent = [NSMutableString stringWithContentsOfFile:projectFilePath encoding:NSUTF8StringEncoding error:&error];
            if (error) {
                printf("打开工程文件 %s 失败：%s\n", projectFilePath.UTF8String, error.localizedDescription.UTF8String);
                return ;
            }
            
            [self modifyClassNamePrefix:projectContent
                           sourceCodeDir:[LZSpamCodeManager shareInstance].gSourceCodeDir
                          ignoreDirNames:[LZSpamCodeManager shareInstance].gIgnoreDirNames
                                 oldName:gOldClassNamePrefix
                                 newName:gNewClassNamePrefix];
            
            [projectContent writeToFile:projectFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        }
        printf("修改类名前缀完成\n");
    }
}

#pragma mark - 文件名、引用修改
+(void)modifyFilesClassName:(NSString *)sourceCodeDir
               oldClassName:(NSString *)oldClassName
               newClassName:(NSString *)newClassName {
    // 文件内容 Const > DDConst (h,m,swift,xib,storyboard)
    NSFileManager *fm = [NSFileManager defaultManager];
    NSArray<NSString *> *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil];
    BOOL isDirectory;
    for (NSString *filePath in files) {
        NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath];
        if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) {
//            if ([[LZSpamCodeManager shareInstance].gIgnoreDirNames containsObject:filePath]){
//                continue;
//            }
            
            [self modifyFilesClassName:path oldClassName:oldClassName newClassName:newClassName];
            continue;
        }
        
        //遍历文件，查找修改引用
        NSString *fileName = filePath.lastPathComponent;
        if ([fileName hasSuffix:@".h"] || [fileName hasSuffix:@".m"] || [fileName hasSuffix:@".pch"] || [fileName hasSuffix:@".swift"] || [fileName hasSuffix:@".xib"] || [fileName hasSuffix:@".storyboard"]) {
            
            NSError *error = nil;
            NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
            if (error) {
                printf("打开文件 %s 失败：%s\n", path.UTF8String, error.localizedDescription.UTF8String);
                abort();
            }
            
            //拦截某个文件
//            if ([fileName containsString:@"AsktaoViewModel"] && [oldClassName isEqualToString:@"AsktaoModel"]) {
//                error = nil;
//            }
            
            NSString *regularExpression = [NSString stringWithFormat:@"\\b%@\\b", oldClassName];
            BOOL isChanged = [LZFileManager regularReplacement:fileContent regularExpression:regularExpression newString:newClassName];
            if (!isChanged) continue;
            error = nil;
            [fileContent writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error];
            if (error) {
                printf("保存文件 %s 失败：%s\n", path.UTF8String, error.localizedDescription.UTF8String);
                abort();
            }
        }
    }
}

#pragma mark - 文件、文件夹改名逻辑判断
+ (void)modifyClassNamePrefix:(NSMutableString *)projectContent
               sourceCodeDir:(NSString *)sourceCodeDir
              ignoreDirNames:(NSArray<NSString *> *)ignoreDirNames
                     oldName:(NSString *)oldName
                     newName:(NSString *)newName{
    
    NSFileManager *fm = [NSFileManager defaultManager];
    
    // 遍历源代码文件 h 与 m 配对，swift
    NSArray<NSString *> *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil];
    BOOL isDirectory;
    for (NSString *filePath in files) {
        NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath];
        if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) {
            if (![ignoreDirNames containsObject:filePath]) {

                [self modifyClassNamePrefix:projectContent sourceCodeDir:path ignoreDirNames:ignoreDirNames oldName:oldName newName:newName];
            }
            continue;
        }
        
        NSString *fileName = filePath.lastPathComponent.stringByDeletingPathExtension;
        NSString *fileExtension = filePath.pathExtension;
        NSString *newClassName;
        
        BOOL isSystemCategory = NO;
        
        if ([fileName hasPrefix:oldName]) {
            newClassName = [newName stringByAppendingString:[fileName substringFromIndex:oldName.length]];
        }else if ([fileName hasPrefix:newName]) {
            //已经改过了的
            newClassName = [newName stringByAppendingString:[fileName substringFromIndex:newName.length]];
//            continue;
        }else if([fileName containsString:@"+"]){
            //处理是category的情况。当是category时，修改+号后面的类名前缀
            
            for (NSString *systemPrefix in [LZSpamCodeManager shareInstance].gSystemPrefixArray) {
                if ([fileName hasPrefix:systemPrefix]) {
                    isSystemCategory = YES;
                }
            }
            
            NSArray *names = [fileName componentsSeparatedByString:@"+"];
            NSMutableString *fileNameStr = [[NSMutableString alloc] initWithString:fileName];
            
            if (isSystemCategory) {
                // NSString+AES128
                NSString *lastName = names.lastObject;
                NSString *newLastName = lastName;
                if ([lastName containsString:oldName]) {//已经改过了的
                    // NSString+XHMBAES128 => NSString+XXXXAES128
                    newLastName = [lastName stringByReplacingOccurrencesOfString:oldName withString:@""];
                }
                
                if ([lastName containsString:newName]) {//已经改过了的
                    // NSString+XHMBAES128 => NSString+XXXXAES128
                    newLastName = [lastName stringByReplacingOccurrencesOfString:newName withString:@""];
                }
                // =>  NSString+XXXXAES128
                [fileNameStr replaceCharactersInRange:[fileName rangeOfString:lastName] withString:[NSString stringWithFormat:@"%@%@",newName,newLastName]];
                newClassName = fileNameStr;
            }else{
                // AppCenter+AES128 => XXXXAppCenter+AES128
                newClassName = [newName stringByAppendingString:fileName];
            }
            
        } else {
            // AppCenter => XXXXAppCenter
            newClassName = [newName stringByAppendingString:fileName];
        }
        //.DS_Store
        // 文件名 Const.ext > DDConst.ext
        if ([fileExtension isEqualToString:@"h"]) {
            NSString *mFileName = [fileName stringByAppendingPathExtension:@"m"];
            if ([files containsObject:mFileName]) {
                
                NSString *oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"];
                NSString *newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"h"];
                
                [LZFileManager renameFile:oldFilePath newPath:newFilePath];
                oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"m"];
                newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"m"];
                
                [LZFileManager renameFile:oldFilePath newPath:newFilePath];
                oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"xib"];
                if ([fm fileExistsAtPath:oldFilePath]) {
                    newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"xib"];
                    [LZFileManager renameFile:oldFilePath newPath:newFilePath];
                }
                
                @autoreleasepool {
                    [self modifyFilesClassName:[LZSpamCodeManager shareInstance].gSourceCodeDir oldClassName:fileName newClassName:newClassName];
                }
            } else {
                continue;
            }
        } else if ([fileExtension isEqualToString:@"swift"]) {
            NSString *oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"swift"];
            NSString *newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"swift"];
            
            [LZFileManager renameFile:oldFilePath newPath:newFilePath];
            oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"xib"];
            
            if ([fm fileExistsAtPath:oldFilePath]) {
                newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"xib"];
                [LZFileManager renameFile:oldFilePath newPath:newFilePath];
            }
            
            @autoreleasepool {
                [self modifyFilesClassName:[LZSpamCodeManager shareInstance].gSourceCodeDir oldClassName:fileName.stringByDeletingPathExtension newClassName:newClassName];
            }
        } else {
            continue;
        }
        
        NSString *regularExpression = [NSString stringWithFormat:@"\\b%@\\b", fileName];
        [LZFileManager regularReplacement:projectContent regularExpression:regularExpression newString:newClassName];
        if (![fileName isEqualToString:[LZSpamCodeManager shareInstance].gOldProjectName]) {
            //当文件和文件夹同名时，修改文件名时会把文件夹的引用也改了，所以得再次改回来
            //把同名文件夹path引用修改过来
            NSString *dirPathExpression = [NSString stringWithFormat:@"path = %@;", newClassName];
            [LZFileManager regularReplacement:projectContent regularExpression:dirPathExpression newString:[NSString stringWithFormat:@"path = %@;", fileName]];
        }
    }
}

@end
